#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext, simpledialog
from PIL import Image, ImageTk
import pytesseract
import threading

class OCRApp:
    def __init__(self, root):
        self.root = root
        self.root.title("文字识别工具")
        self.root.geometry("800x600")
        self.root.minsize(800, 600)
        
        # 设置应用程序主题
        self.root.configure(bg="#f0f0f0")
        
        # 创建菜单栏
        self.create_menu()
        
        # 创建主布局
        self.create_layout()
        
        # 初始化变量
        self.image_path = None
        self.current_image = None
        self.is_processing = False
        
    def create_menu(self):
        menubar = tk.Menu(self.root)
        
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label="打开图片", command=self.open_image)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        
        settings_menu = tk.Menu(menubar, tearoff=0)
        settings_menu.add_command(label="设置Tesseract路径", command=self.set_tesseract_path)
        
        help_menu = tk.Menu(menubar, tearoff=0)
        help_menu.add_command(label="关于", command=self.show_about)
        
        menubar.add_cascade(label="文件", menu=file_menu)
        menubar.add_cascade(label="设置", menu=settings_menu)
        menubar.add_cascade(label="帮助", menu=help_menu)
        
        self.root.config(menu=menubar)
    
    def create_layout(self):
        # 创建上下分割的布局
        self.main_frame = tk.Frame(self.root, bg="#f0f0f0")
        self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 上部：图片显示区域和按钮
        self.top_frame = tk.Frame(self.main_frame, bg="#f0f0f0")
        self.top_frame.pack(fill=tk.BOTH, expand=True)
        
        # 图片显示区域
        self.image_frame = tk.LabelFrame(self.top_frame, text="图片预览", bg="#f0f0f0")
        self.image_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.image_label = tk.Label(self.image_frame, bg="#ffffff", text="暂无图片\n\n请通过菜单或下方按钮选择图片")
        self.image_label.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 按钮区域
        self.button_frame = tk.Frame(self.top_frame, bg="#f0f0f0", width=150)
        self.button_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=5, pady=5)
        
        self.open_button = tk.Button(self.button_frame, text="选择图片", command=self.open_image, width=15)
        self.open_button.pack(pady=(20, 10))
        
        self.process_button = tk.Button(self.button_frame, text="开始识别", command=self.process_image, width=15, state=tk.DISABLED)
        self.process_button.pack(pady=10)
        
        self.clear_button = tk.Button(self.button_frame, text="清除", command=self.clear_all, width=15, state=tk.DISABLED)
        self.clear_button.pack(pady=10)
        
        self.copy_button = tk.Button(self.button_frame, text="复制文本", command=self.copy_text, width=15, state=tk.DISABLED)
        self.copy_button.pack(pady=10)
        
        # 下部：识别结果区域
        self.bottom_frame = tk.LabelFrame(self.main_frame, text="识别结果", bg="#f0f0f0")
        self.bottom_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.result_text = scrolledtext.ScrolledText(self.bottom_frame, wrap=tk.WORD, bg="#ffffff", height=10)
        self.result_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 状态栏
        self.status_var = tk.StringVar()
        self.status_var.set("就绪")
        self.status_bar = tk.Label(self.root, textvariable=self.status_var, bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
    def set_tesseract_path(self):
        """允许用户设置Tesseract路径"""
        
        # 获取当前路径
        current_path = pytesseract.pytesseract.tesseract_cmd or ""
        
        # 询问新路径
        if sys.platform == 'win32':
            new_path = filedialog.askopenfilename(
                title="选择Tesseract可执行文件",
                filetypes=[("可执行文件", "*.exe"), ("所有文件", "*.*")],
                initialfile=current_path
            )
        else:
            # 在Linux/Mac上默认tesseract通常在PATH中，所以直接询问路径
            new_path = simpledialog.askstring(
                "Tesseract路径", 
                "请输入Tesseract可执行文件的路径:",
                initialvalue=current_path
            )
        
        if new_path:
            # 验证路径
            if os.path.exists(new_path):
                pytesseract.pytesseract.tesseract_cmd = new_path
                
                # 更新.env文件
                try:
                    from dotenv import set_key
                    set_key('.env', 'TESSERACT_CMD_PATH', new_path)
                    messagebox.showinfo("成功", f"Tesseract路径已更新为:\n{new_path}\n\n设置已保存到.env文件")
                except Exception as e:
                    # 如果dotenv更新失败，仍然设置路径但显示警告
                    messagebox.showwarning("部分成功", f"Tesseract路径已更新，但无法保存到.env文件:\n{str(e)}")
            else:
                messagebox.showerror("错误", f"指定的路径不存在:\n{new_path}")
    
    def open_image(self):
        file_types = [
            ("图片文件", "*.png;*.jpg;*.jpeg;*.bmp;*.tiff"),
            ("所有文件", "*.*")
        ]
        
        file_path = filedialog.askopenfilename(filetypes=file_types)
        
        if file_path:
            try:
                self.image_path = file_path
                self.display_image(file_path)
                self.status_var.set(f"已加载图片: {os.path.basename(file_path)}")
                self.process_button.config(state=tk.NORMAL)
                self.clear_button.config(state=tk.NORMAL)
            except Exception as e:
                messagebox.showerror("错误", f"无法打开图片: {str(e)}")
    
    def display_image(self, file_path):
        # 打开图片并调整大小适应显示区域
        image = Image.open(file_path)
        
        # 获取图片尺寸和显示区域尺寸
        image_width, image_height = image.size
        frame_width = self.image_label.winfo_width()
        frame_height = self.image_label.winfo_height()
        
        # 如果窗口尚未渲染完毕，则使用预估值
        if frame_width <= 1:
            frame_width = 400
        if frame_height <= 1:
            frame_height = 300
        
        # 计算缩放比例
        width_ratio = frame_width / image_width
        height_ratio = frame_height / image_height
        ratio = min(width_ratio, height_ratio) * 0.9  # 乘以0.9留出边距
        
        # 计算新尺寸
        new_width = int(image_width * ratio)
        new_height = int(image_height * ratio)
        
        # 调整图片大小
        resized_image = image.resize((new_width, new_height), Image.LANCZOS)
        
        # 转换为Tkinter可用的格式
        self.current_image = ImageTk.PhotoImage(resized_image)
        
        # 显示图片
        self.image_label.config(image=self.current_image, text="")
    
    def process_image(self):
        if self.is_processing:
            return
        
        if not self.image_path:
            messagebox.showinfo("提示", "请先选择一张图片")
            return
        
        # 检查Tesseract是否可用
        if not check_tesseract():
            result = messagebox.askquestion(
                "Tesseract未配置", 
                "未检测到Tesseract-OCR引擎，OCR功能将无法使用。\n\n是否现在配置Tesseract路径？"
            )
            if result == 'yes':
                self.set_tesseract_path()
                # 如果用户设置了路径，再次检查
                if not check_tesseract():
                    return
            else:
                return
        
        self.is_processing = True
        self.status_var.set("正在处理中...")
        self.process_button.config(state=tk.DISABLED)
        
        # 清除之前的结果
        self.result_text.delete(1.0, tk.END)
        
        # 创建线程进行OCR处理
        thread = threading.Thread(target=self.run_ocr)
        thread.daemon = True
        thread.start()
    
    def run_ocr(self):
        try:
            # 打开图片
            image = Image.open(self.image_path)
            
            # 使用pytesseract进行OCR识别
            text = pytesseract.image_to_string(image, lang='chi_sim+eng')
            
            # 在主线程中更新UI
            self.root.after(0, self.update_result, text)
        except Exception as e:
            self.root.after(0, self.show_error, str(e))
    
    def update_result(self, text):
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, text)
        self.status_var.set("识别完成")
        self.process_button.config(state=tk.NORMAL)
        self.copy_button.config(state=tk.NORMAL)
        self.is_processing = False
    
    def show_error(self, error_message):
        messagebox.showerror("错误", f"OCR处理失败: {error_message}")
        self.status_var.set("处理出错")
        self.process_button.config(state=tk.NORMAL)
        self.is_processing = False
    
    def clear_all(self):
        self.image_path = None
        self.image_label.config(image="", text="暂无图片\n\n请通过菜单或下方按钮选择图片")
        self.current_image = None
        self.result_text.delete(1.0, tk.END)
        self.status_var.set("就绪")
        self.process_button.config(state=tk.DISABLED)
        self.clear_button.config(state=tk.DISABLED)
        self.copy_button.config(state=tk.DISABLED)
    
    def copy_text(self):
        text = self.result_text.get(1.0, tk.END).strip()
        if text:
            self.root.clipboard_clear()
            self.root.clipboard_append(text)
            self.status_var.set("文本已复制到剪贴板")
        else:
            messagebox.showinfo("提示", "没有可复制的文本")
    
    def show_about(self):
        about_message = "OCR文字识别工具 v1.0\n\n"
        about_message += "© 2025 版权所有\n\n"
        about_message += "这是一个简单的OCR文字识别工具，可以从图片中提取文字。\n"
        about_message += "使用了Tesseract-OCR引擎和Python。\n\n"
        about_message += "要使用本工具，请确保已安装Tesseract-OCR，\n"
        about_message += "或在'设置'菜单中配置Tesseract路径。"
        
        messagebox.showinfo("关于", about_message)

def check_tesseract():
    """检查Tesseract是否安装和配置正确"""
    try:
        pytesseract.get_tesseract_version()
        return True
    except Exception:
        return False

def main():
    # 检查Tesseract
    tesseract_available = check_tesseract()
    if not tesseract_available:
        print("警告: 未检测到Tesseract-OCR引擎")
        print("请确保安装了Tesseract-OCR并将其添加到系统PATH中")
        print("或者在应用程序内通过'设置'菜单手动设置路径")
    
    root = tk.Tk()
    app = OCRApp(root)
    root.mainloop()

if __name__ == "__main__":
    main() 